#include "MemoryAlloc.h"
#include <stdexcept>
#include <iostream>

MemoryAlloc::MemoryAlloc(HANDLE process, DWORD size, void* base, DWORD protection):
m_process(process),
m_baseAddress(0),
m_size(size)
{
	m_baseAddress = static_cast<char*>(VirtualAllocEx(m_process, base, m_size, MEM_RESERVE | MEM_COMMIT, protection));
	if (m_baseAddress == NULL)
		throw std::runtime_error("MemoryAlloc::MemoryAlloc - Memory could not be allocated.");
}
MemoryAlloc::MemoryAlloc(MemoryAlloc&& rhs):
m_process(rhs.m_process),
m_baseAddress(rhs.m_baseAddress),
m_size(rhs.m_size)
{
	rhs.m_process = NULL;
	rhs.m_baseAddress = 0;
	rhs.m_size = 0;
}
MemoryAlloc::~MemoryAlloc(void)
{
	if (m_baseAddress)
		VirtualFreeEx(m_process, m_baseAddress, 0, MEM_RELEASE);
}
MemoryAlloc& MemoryAlloc::operator=(MemoryAlloc&& rhs)
{
	if (m_baseAddress)
		VirtualFreeEx(m_process, m_baseAddress, 0, MEM_RELEASE);

	m_process = rhs.m_process;
	m_baseAddress = rhs.m_baseAddress;
	m_size = rhs.m_size;

	rhs.m_process = NULL;
	rhs.m_baseAddress = 0;
	rhs.m_size = 0;

	return *this;
}
char MemoryAlloc::operator[](int index)
{
	char c = 0;
	Read(index, &c, 1);
	return c;
}
void MemoryAlloc::Write(DWORD offset, const void* data, DWORD size) const
{
	if (m_baseAddress + m_size < m_baseAddress + offset + size)
		throw std::runtime_error("MemoryAlloc::Write - Out of bounds.");

	DWORD bytesWritten = 0;
	BOOL result = WriteProcessMemory(m_process, m_baseAddress + offset, data, size, &bytesWritten);
	if (result == FALSE)
		throw std::runtime_error("MemoryAlloc::Write - Memory writing failed.");

	if (bytesWritten < size)
		throw std::runtime_error("MemoryAlloc::Write - The amount of bytes written differs from size specified.");
}
void MemoryAlloc::Read(DWORD offset, void* buffer, DWORD size) const
{
	DWORD bytesRead = 0;
	BOOL result = ReadProcessMemory(m_process, m_baseAddress + offset, buffer, size, &bytesRead);
	if (result == FALSE)
		throw std::runtime_error("MemoryAlloc::Read - Memory reading failed.");

	if (bytesRead < size)
		throw std::runtime_error("MemoryAlloc::Read - The amount of bytes read differs from size specified.");
}
void* MemoryAlloc::GetAddress(void) const
{
	return m_baseAddress;
}